package cc.shacocloud.mirage.utils.collection;

import lombok.Getter;
import org.jetbrains.annotations.NotNull;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 自排序集合，使用 {@link Comparable} 获取对面的排序值，基于{@link ArrayList} 实现，所以是非线程安全对象，请注意使用
 * <p>
 * 如果需要线程安全可以配合 {@link Collections#synchronizedList(List)} 使用
 *
 * @param <E> 泛型实例
 */
public class SelfSortList<E> implements List<E> {
    
    /**
     * 默认初始容量
     */
    public static final int DEFAULT_CAPACITY = 10;
    private final Comparable<E> comparable;
    private final ArrayList<WrapNode<E>> arr;
    
    /**
     * @param comparable 获取当前对象排序所用值的函数
     */
    public SelfSortList(Comparable<E> comparable) {
        this(DEFAULT_CAPACITY, comparable);
    }
    
    /**
     * @param initialCapacity 初始长度
     * @param comparable      获取当前对象排序所用值的函数
     */
    public SelfSortList(int initialCapacity, Comparable<E> comparable) {
        this.comparable = comparable;
        this.arr = new ArrayList<>(initialCapacity);
    }
    
    @Override
    public int size() {
        return this.arr.size();
    }
    
    @Override
    public boolean isEmpty() {
        return this.arr.isEmpty();
    }
    
    @Override
    public boolean contains(Object o) {
        return this.arr.contains(new WrapNode<>(o));
    }
    
    @NotNull
    @Override
    public Iterator<E> iterator() {
        return this.arr.stream().map(WrapNode::getNode).iterator();
    }
    
    @Override
    public Object[] toArray() {
        return this.arr.stream().map(WrapNode::getNode).toArray();
    }
    
    @Override
    public <T> T[] toArray(T[] a) {
        return this.arr.stream().map(WrapNode::getNode).collect(Collectors.toList()).toArray(a);
    }
    
    @Override
    public boolean add(E e) {
        int v = comparable.compareTo(e);
        
        int size = this.arr.size();
        for (int i = 0; i < size; i++) {
            WrapNode<E> t = this.arr.get(i);
            if (v < t.getV()) {
                this.arr.add(i, new WrapNode<>(v, e));
                return true;
            }
        }
        
        return this.arr.add(new WrapNode<>(v, e));
    }
    
    @Override
    public boolean remove(Object o) {
        return this.arr.remove(new WrapNode<>(o));
    }
    
    @Override
    public boolean containsAll(Collection<?> c) {
        return this.arr.containsAll(c.stream().map(WrapNode::new).collect(Collectors.toList()));
    }
    
    @Override
    public void add(int index, E element) {
        throw new UnsupportedOperationException();
    }
    
    @Override
    public E remove(int index) {
        throw new UnsupportedOperationException();
    }
    
    @Override
    public int indexOf(Object o) {
        return this.arr.indexOf(new WrapNode<>(o));
    }
    
    @Override
    public int lastIndexOf(Object o) {
        return this.arr.lastIndexOf(new WrapNode<>(o));
    }
    
    @Override
    public ListIterator<E> listIterator() {
        throw new UnsupportedOperationException();
    }
    
    @Override
    public ListIterator<E> listIterator(int index) {
        throw new UnsupportedOperationException();
    }
    
    @Override
    public List<E> subList(int fromIndex, int toIndex) {
        return this.arr.subList(fromIndex, toIndex).stream().map(WrapNode::getNode).collect(Collectors.toList());
    }
    
    @Override
    public boolean addAll(Collection<? extends E> c) {
        for (E e : c) {
            add(e);
        }
        return true;
    }
    
    @Override
    public boolean addAll(int index, Collection<? extends E> c) {
        throw new UnsupportedOperationException();
    }
    
    @Override
    public boolean removeAll(Collection<?> c) {
        return this.arr.removeAll(c.stream().map(WrapNode::new).collect(Collectors.toList()));
    }
    
    @Override
    public boolean retainAll(Collection<?> c) {
        return this.arr.retainAll(c.stream().map(WrapNode::new).collect(Collectors.toList()));
    }
    
    @Override
    public E set(int index, E element) {
        throw new UnsupportedOperationException();
    }
    
    @Override
    public void sort(Comparator<? super E> c) {
        // 什么也不做...
    }
    
    @Override
    public void clear() {
        this.arr.clear();
    }
    
    @Override
    public E get(int index) {
        return this.arr.get(index).getNode();
    }
    
    @Override
    public String toString() {
        return this.arr.stream().map(WrapNode::getNode).collect(Collectors.toList()).toString();
    }
    
    /**
     * 包装节点信息，来减少 {@link Comparable#compareTo(Object)} 方法的调用
     *
     * @param <E>
     */
    @Getter
    private static class WrapNode<E> {
        
        private final E node;
        private int v;
        
        public WrapNode(int v, E node) {
            this.v = v;
            this.node = node;
        }
        
        public WrapNode(E node) {
            this.node = node;
        }
        
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            WrapNode<?> wrapNode = (WrapNode<?>) o;
            return node.equals(wrapNode.node);
        }
        
        @Override
        public int hashCode() {
            return Objects.hash(node);
        }
    }
    
}
